#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/msg.h>

#define PORT 8080
#define BACKLOG 5
#define BUFFER_SIZE 1024

// 共享内存相关变量
int shmid1, shmid2;
char *shmaddr1, *shmaddr2;

// 消息队列相关变量
int msqid1, msqid2;

// 消息结构体
struct message {
    long mtype;
    char mtext[BUFFER_SIZE];
};

// 线程函数，用于将数据写入共享内存
void *write_to_shm1(void *arg) {
    char *data = (char *)arg;

    // 连接到共享内存
    shmaddr1 = shmat(shmid1, NULL, 0);
    if (shmaddr1 == (void *)-1) {
        perror("shmat");
        pthread_exit(NULL);
    }

    // 将数据写入共享内存
    strncpy(shmaddr1, data, BUFFER_SIZE);

    // 断开共享内存连接
    shmdt(shmaddr1);

    pthread_exit(NULL);
}

void *write_to_shm2(void *arg) {
    char *data = (char *)arg;

    // 连接到共享内存
    shmaddr2 = shmat(shmid2, NULL, 0);
    if (shmaddr2 == (void *)-1) {
        perror("shmat");
        pthread_exit(NULL);
    }

    // 将数据写入共享内存
    strncpy(shmaddr2, data, BUFFER_SIZE);

    // 断开共享内存连接
    shmdt(shmaddr2);

    pthread_exit(NULL);
}

// 线程函数，用于从消息队列接收数据并通过WiFi发送给客户端
void *receive_from_msg_queue1(void *arg) {
    struct message msg;
    int client_socket = *(int *)arg;

    while (1) {
        // 从消息队列接收数据
        if (msgrcv(msqid1, &msg, sizeof(msg.mtext), 1, 0) == -1) {
            perror("msgrcv");
            continue;
        }

        printf("Received message from queue1: %s\n", msg.mtext);

        // 将消息通过WiFi发送给客户端
        if (send(client_socket, msg.mtext, strlen(msg.mtext), 0) < 0) {
            perror("send");
            continue;
        }

        printf("Message sent to client from queue1: %s\n", msg.mtext);
    }

    pthread_exit(NULL);
}

void *receive_from_msg_queue2(void *arg) {
    struct message msg;
    int client_socket = *(int *)arg;

    while (1) {
        // 从消息队列接收数据
        if (msgrcv(msqid2, &msg, sizeof(msg.mtext), 1, 0) == -1) {
            perror("msgrcv");
            continue;
        }

        printf("Received message from queue2: %s\n", msg.mtext);

        // 将消息通过WiFi发送给客户端
        if (send(client_socket, msg.mtext, strlen(msg.mtext), 0) < 0) {
            perror("send");
            continue;
        }

        printf("Message sent to client from queue2: %s\n", msg.mtext);
    }

    pthread_exit(NULL);
}

int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[BUFFER_SIZE] = {0};
    pthread_t tcp_thread1, tcp_thread2, msg_queue_thread1, msg_queue_thread2;

    // 创建共享内存
    shmid1 = shmget(0x123, BUFFER_SIZE, IPC_CREAT | 0666);
    if (shmid1 < 0) {
        perror("shmget");
        exit(EXIT_FAILURE);
    }
    printf("共享内存1创建成功\n");

    shmid2 = shmget(0x124, BUFFER_SIZE, IPC_CREAT | 0666);
    if (shmid2 < 0) {
        perror("shmget");
        exit(EXIT_FAILURE);
    }
    printf("共享内存2创建成功\n");

    // 创建消息队列
    msqid1 = msgget(0x001, IPC_CREAT | 0666);
    if (msqid1 < 0) {
        perror("msgget");
        exit(EXIT_FAILURE);
    }
    printf("消息队列1创建成功\n");

    msqid2 = msgget(0x002, IPC_CREAT | 0666);
    if (msqid2 < 0) {
        perror("msgget");
        exit(EXIT_FAILURE);
    }
    printf("消息队列2创建成功\n");

    // 创建 socket
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // 限制地址重用
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }

    // 配置服务器地址结构
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY; // 监听所有接口
    address.sin_port = htons(PORT); // 指定端口

    // 绑定 socket
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    // 开始监听
    if (listen(server_fd, BACKLOG) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }

    printf("TCP server is listening on port %d\n", PORT);

    while (1) {
        // 接受客户端连接
        if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
            perror("accept");
            exit(EXIT_FAILURE);
        }

        printf("New connection accepted\n");

        // 创建线程处理消息队列的接收和发送
        if (pthread_create(&msg_queue_thread1, NULL, receive_from_msg_queue1, (void *)&new_socket) != 0) {
            perror("pthread_create");
            close(new_socket);
            continue;
        }

        if (pthread_create(&msg_queue_thread2, NULL, receive_from_msg_queue2, (void *)&new_socket) != 0) {
            perror("pthread_create");
            close(new_socket);
            continue;
        }

        // 持续读取客户端发送的数据
        while (1) {
            // 读取数据
            int valread = read(new_socket, buffer, BUFFER_SIZE);
            if (valread < 0) {
                perror("read");
                break; // 读取失败，退出循环
            } else if (valread == 0) {
                printf("Client disconnected\n");
                break; // 客户端断开连接，退出循环
            }

            // 打印接收到的字符串数据
            buffer[valread] = '\0'; // 确保字符串以 null 结尾
            printf("Received data: %s\n", buffer);

            // 创建线程将数据写入共享内存
            if (pthread_create(&tcp_thread1, NULL, write_to_shm1, (void *)buffer) != 0) {
                perror("pthread_create");
                continue;
            }

            if (pthread_create(&tcp_thread2, NULL, write_to_shm2, (void *)buffer) != 0) {
                perror("pthread_create");
                continue;
            }

            // 发送回应
            const char *message = "Hello from server";
            send(new_socket, message, strlen(message), 0);
            printf("Message sent\n");

            // 等待线程结束
            pthread_join(tcp_thread1, NULL);
            pthread_join(tcp_thread2, NULL);
        }

        // 关闭连接
        close(new_socket);
    }

    // 删除共享内存
    shmctl(shmid1, IPC_RMID, NULL);
    shmctl(shmid2, IPC_RMID, NULL);

    // 删除消息队列
    msgctl(msqid1, IPC_RMID, NULL);
    msgctl(msqid2, IPC_RMID, NULL);

    return 0;
}
